package pay

import (
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"encoding/xml"
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/silenceper/wechat"
	"github.com/silenceper/wechat/pay"
	"go-admin-official/modules/config"
	"go-admin-official/modules/logger"
	"io/ioutil"
	"sort"
	"strings"
)

var wxClient = new(wechat.Wechat)

func InitWxPay() {
	wxClient = wechat.NewWechat(&wechat.Config{
		AppID:        config.Get().WxPayAppID,
		AppSecret:    config.Get().WxPayAppSecret,
		Token:        "",
		PayMchID:     config.Get().WxPayMchID,
		PayNotifyURL: "http://goadmin.ng.dadadaa.com/api/pay/callback",
		PayKey:       config.Get().WxPayKey,
	})
}

const wxNotifyURL = "http://goadmin.ng.dadadaa.com/api/pay/callback"

func GetWxpayCode(no, title, amount string) (string, error) {

	order, err := wxClient.GetPay().PrePayOrder(&pay.Params{
		TotalFee:   "3",
		CreateIP:   "127.0.0.1",
		Body:       title,
		OutTradeNo: no,
		TradeType:  "NATIVE",
		NotifyURL:  wxNotifyURL,
	})

	if err != nil {
		logger.Error("GetWxpayCode error: ", err, "order", no)
		return "", err
	}

	if order.ReturnCode != "SUCCESS" {
		logger.Error("GetWxpayCode error: ", order.ReturnMsg, "order", no)
		return "", errors.New(order.ReturnMsg)
	}

	return order.CodeURL, nil
}

func GetWxNotifyReturnMsg(ctx *gin.Context) (string, string, string, bool, error) {
	body, err := ioutil.ReadAll(ctx.Request.Body)

	if err != nil {
		return "", "", "", false, err
	}

	var res pay.NotifyResult

	err = xml.Unmarshal(body, &res)

	if err != nil {
		return "", "", "", false, err
	}

	if !wxClient.GetPay().VerifySign(res) {
		return "", "", "", false, errors.New("验证签名失败")
	}

	return res.OutTradeNo, res.OutTradeNo, string(body), res.ResultCode == "SUCCESS", nil
}

func Sign(params map[string]string, secret string) string {
	var keys = make([]string, 0, len(params))
	for k := range params {
		if k != "sign" {
			keys = append(keys, k)
		}
	}
	sort.Strings(keys)

	var buf bytes.Buffer
	for _, k := range keys {
		if params[k] != "" {
			buf.WriteString(k)
			buf.WriteString(`=`)
			buf.WriteString(params[k])
			buf.WriteString(`&`)
		}
	}
	buf.WriteString(`key=`)
	buf.WriteString(secret)

	sum := md5.Sum(buf.Bytes())
	str := hex.EncodeToString(sum[:])

	return strings.ToUpper(str)
}
